import { getToken } from '@/utils/auth'

/**
 * WebSocket工具类
 * 用于管理WebSocket连接，接收实时报警信息
 */
class WebSocketClient {
  constructor(url, options = {}) {
    this.url = url
    this.options = {
      reconnectInterval: options.reconnectInterval || 3000, // 初始重连间隔（毫秒）
      maxReconnectInterval: options.maxReconnectInterval || 30000, // 最大重连间隔（毫秒）
      maxReconnectAttempts: options.maxReconnectAttempts || 0, // 最大重连次数（0表示无限重连）
      heartbeatInterval: options.heartbeatInterval || 30000, // 心跳间隔（毫秒）
      heartbeatTimeout: options.heartbeatTimeout || 10000, // 心跳超时时间（毫秒）
      useExponentialBackoff: options.useExponentialBackoff !== false, // 是否使用指数退避
      ...options
    }
    this.ws = null
    this.reconnectAttempts = 0
    this.heartbeatTimer = null
    this.heartbeatTimeoutTimer = null
    this.reconnectTimer = null
    this.listeners = new Map() // 存储事件监听器
    this.isManualClose = false // 是否手动关闭
    this.isReconnecting = false // 是否正在重连
    this.lastHeartbeatTime = null // 最后一次心跳时间
  }

  /**
   * 连接WebSocket
   */
  connect() {
    // 如果已经连接，直接返回
    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
      console.log('WebSocket已经连接')
      return
    }

    // 如果正在连接中，不重复连接
    if (this.ws && this.ws.readyState === WebSocket.CONNECTING) {
      console.log('WebSocket正在连接中...')
      return
    }

    // 清理旧的连接
    if (this.ws) {
      try {
        this.ws.onopen = null
        this.ws.onmessage = null
        this.ws.onerror = null
        this.ws.onclose = null
        if (this.ws.readyState !== WebSocket.CLOSED) {
          this.ws.close()
        }
      } catch (e) {
        console.warn('清理旧连接时出错:', e)
      }
      this.ws = null
    }

    try {
      let wsUrl = this.url


      // 判断协议，开发环境使用ws，生产环境根据实际配置
      const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
      
      // 获取后端地址
      let host
      let fullUrl
      
      if (process.env.NODE_ENV === 'production') {
        // 生产环境：使用当前页面的host和port
        // window.location.host 在非默认端口时包含端口，默认端口时不包含
        // window.location.hostname 不包含端口
        // window.location.port 包含端口号（如果是默认端口则为空字符串）
        const hostname = window.location.hostname
        const port = window.location.port
        
        // 构建host，确保包含端口（除非是默认端口）
        if (port) {
          // 有明确端口号
          host = `${hostname}:${port}`
        } else {
          // 默认端口（80或443），window.location.host 已经处理好了
          host = window.location.host || hostname
        }
        
        // WebSocket路径使用绝对路径，会自动相对于当前页面的context-path
        fullUrl = `${protocol}//${host}${wsUrl}`
      } else {
        // 开发环境：直接连接后端（不使用代理，因为WebSocket代理已移除）
        // 从vue.config.js的baseUrl中提取端口，默认8080
        const backendPort = '8080' // 默认后端端口
        host = `localhost:${backendPort}`
        fullUrl = `${protocol}//${host}${wsUrl}`
      }
      
      // 可选：添加token到URL参数（如果需要认证）
      // const token = getToken()
      // if (token) {
      //   fullUrl += (fullUrl.indexOf('?') > -1 ? '&' : '?') + `token=${encodeURIComponent(token)}`
      // }
      
      console.log('正在连接WebSocket:', fullUrl, '环境:', process.env.NODE_ENV, '当前页面:', window.location.href)
      console.log('WebSocket连接详情:', {
        url: fullUrl,
        protocol: protocol,
        host: host,
        wsUrl: wsUrl,
        environment: process.env.NODE_ENV
      })
      this.ws = new WebSocket(fullUrl)

      this.ws.onopen = (event) => {
        console.log('WebSocket连接成功', event)
        const wasReconnecting = this.isReconnecting
        this.reconnectAttempts = 0
        this.isManualClose = false
        this.isReconnecting = false
        this.lastHeartbeatTime = Date.now()
        this.startHeartbeat()
        this.emit('open', event)
        // 只有在重连成功时才触发reconnect-success事件
        if (wasReconnecting) {
          this.emit('reconnect-success', { attempts: this.reconnectAttempts })
        }
      }

      this.ws.onmessage = (event) => {
        try {
          console.log('收到WebSocket原始消息:', event.data)
          const data = JSON.parse(event.data)
          console.log('解析后的WebSocket消息:', data)
          
          // 处理心跳响应
          if (data.type === 'pong' || data.type === 'heartbeat' || data.type === 'connected') {
            this.lastHeartbeatTime = Date.now()
            // 清除心跳超时定时器
            if (this.heartbeatTimeoutTimer) {
              clearTimeout(this.heartbeatTimeoutTimer)
              this.heartbeatTimeoutTimer = null
            }
            if (data.type === 'connected') {
              console.log('WebSocket连接确认消息')
            }
            return
          }
          
          console.log('触发message事件，消息类型:', data.type)
          this.emit('message', data)
        } catch (error) {
          console.error('解析WebSocket消息失败:', error, event.data)
          // 如果不是JSON，直接传递原始数据
          this.emit('message', event.data)
        }
      }

      this.ws.onerror = (error) => {
        console.error('WebSocket错误:', error)
        console.error('WebSocket错误详情:', {
          type: error.type,
          target: error.target,
          readyState: error.target?.readyState,
          url: error.target?.url
        })
        this.emit('error', error)
        // 错误时也会触发onclose，所以不需要在这里重连
      }

      this.ws.onclose = (event) => {
        console.log('WebSocket连接关闭', {
          code: event.code,
          reason: event.reason,
          wasClean: event.wasClean,
          url: this.ws?.url
        })
        this.stopHeartbeat()
        this.emit('close', event)
        
        // 如果不是手动关闭，尝试重连
        if (!this.isManualClose) {
          // 检查关闭代码，某些代码不需要重连（如正常关闭、认证失败等）
          if (event.code === 1000) {
            // 正常关闭，不重连
            console.log('WebSocket正常关闭，不重连')
            return
          }
          // 1006表示异常关闭（可能是网络问题或服务器未响应）
          if (event.code === 1006) {
            console.warn('WebSocket异常关闭（1006），可能是连接失败，准备重连')
          }
          this.reconnect()
        } else {
          console.log('WebSocket手动关闭，不重连')
        }
      }
    } catch (error) {
      console.error('创建WebSocket连接失败:', error)
      this.emit('error', error)
      if (!this.isManualClose) {
        this.reconnect()
      }
    }
  }

  /**
   * 重连
   */
  reconnect() {
    // 如果正在重连，不重复触发
    if (this.isReconnecting) {
      return
    }

    // 检查是否达到最大重连次数（0表示无限重连）
    if (this.options.maxReconnectAttempts > 0 && 
        this.reconnectAttempts >= this.options.maxReconnectAttempts) {
      console.error(`WebSocket重连次数已达上限(${this.options.maxReconnectAttempts})，停止重连`)
      this.emit('reconnect-failed', { 
        attempts: this.reconnectAttempts,
        maxAttempts: this.options.maxReconnectAttempts
      })
      return
    }

    this.isReconnecting = true
    this.reconnectAttempts++
    
    // 计算重连间隔（使用指数退避策略）
    let reconnectInterval = this.options.reconnectInterval
    if (this.options.useExponentialBackoff) {
      // 指数退避：每次重连间隔 = 初始间隔 * 2^(重连次数-1)
      reconnectInterval = Math.min(
        this.options.reconnectInterval * Math.pow(2, this.reconnectAttempts - 1),
        this.options.maxReconnectInterval
      )
    }
    
    console.log(`WebSocket准备重连，第${this.reconnectAttempts}次尝试，${reconnectInterval}ms后重连...`)
    
    this.emit('reconnecting', {
      attempts: this.reconnectAttempts,
      maxAttempts: this.options.maxReconnectAttempts,
      interval: reconnectInterval
    })
    
    this.reconnectTimer = setTimeout(() => {
      this.isReconnecting = false
      this.connect()
    }, reconnectInterval)
  }

  /**
   * 发送消息
   */
  send(data) {
    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
      const message = typeof data === 'string' ? data : JSON.stringify(data)
      this.ws.send(message)
    } else {
      console.warn('WebSocket未连接，无法发送消息')
    }
  }

  /**
   * 启动心跳
   */
  startHeartbeat() {
    this.stopHeartbeat()
    this.lastHeartbeatTime = Date.now()
    
    // 立即发送一次心跳，建立初始心跳时间
    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
      this.send({ type: 'ping' })
    }
    
    this.heartbeatTimer = setInterval(() => {
      if (this.ws && this.ws.readyState === WebSocket.OPEN) {
        // 检查上次心跳响应时间，如果超过超时时间则断开重连
        // 注意：这里检查的是从上次收到心跳响应到现在的时间
        // 如果超过超时时间，说明服务器可能已经断开或网络有问题
        if (this.lastHeartbeatTime && 
            Date.now() - this.lastHeartbeatTime > this.options.heartbeatTimeout) {
          console.warn('WebSocket心跳超时（超过', this.options.heartbeatTimeout, 'ms未收到响应），准备重连')
          this.ws.close()
          return
        }
        
        // 发送心跳
        this.send({ type: 'ping' })
        console.debug('发送WebSocket心跳，当前时间:', new Date().toISOString())
        
        // 设置心跳超时定时器
        // 如果发送心跳后，在超时时间内没有收到响应，则断开重连
        if (this.heartbeatTimeoutTimer) {
          clearTimeout(this.heartbeatTimeoutTimer)
        }
        this.heartbeatTimeoutTimer = setTimeout(() => {
          if (this.ws && this.ws.readyState === WebSocket.OPEN) {
            // 再次检查是否收到了响应
            if (this.lastHeartbeatTime && 
                Date.now() - this.lastHeartbeatTime > this.options.heartbeatTimeout) {
              console.warn('WebSocket心跳响应超时（', this.options.heartbeatTimeout, 'ms内未收到响应），准备重连')
              this.ws.close()
            }
          }
        }, this.options.heartbeatTimeout)
      }
    }, this.options.heartbeatInterval)
  }

  /**
   * 停止心跳
   */
  stopHeartbeat() {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer)
      this.heartbeatTimer = null
    }
    if (this.heartbeatTimeoutTimer) {
      clearTimeout(this.heartbeatTimeoutTimer)
      this.heartbeatTimeoutTimer = null
    }
    this.lastHeartbeatTime = null
  }

  /**
   * 关闭连接
   */
  close() {
    this.isManualClose = true
    this.isReconnecting = false
    this.stopHeartbeat()
    
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer)
      this.reconnectTimer = null
    }
    
    if (this.ws) {
      try {
        // 移除事件监听器，避免触发重连
        this.ws.onclose = null
        this.ws.close()
      } catch (e) {
        console.warn('关闭WebSocket连接时出错:', e)
      }
      this.ws = null
    }
  }

  /**
   * 重置重连计数（用于手动重连）
   */
  resetReconnectAttempts() {
    this.reconnectAttempts = 0
    this.isReconnecting = false
  }

  /**
   * 手动重连
   */
  manualReconnect() {
    this.isManualClose = false
    this.resetReconnectAttempts()
    this.close()
    setTimeout(() => {
      this.connect()
    }, 1000)
  }

  /**
   * 添加事件监听器
   */
  on(event, callback) {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, [])
    }
    this.listeners.get(event).push(callback)
  }

  /**
   * 移除事件监听器
   */
  off(event, callback) {
    if (this.listeners.has(event)) {
      const callbacks = this.listeners.get(event)
      const index = callbacks.indexOf(callback)
      if (index > -1) {
        callbacks.splice(index, 1)
      }
    }
  }

  /**
   * 触发事件
   */
  emit(event, data) {
    if (this.listeners.has(event)) {
      this.listeners.get(event).forEach(callback => {
        try {
          callback(data)
        } catch (error) {
          console.error(`执行事件监听器失败 [${event}]:`, error)
        }
      })
    }
  }

  /**
   * 获取连接状态
   */
  getReadyState() {
    if (!this.ws) {
      return WebSocket.CONNECTING
    }
    return this.ws.readyState
  }

  /**
   * 是否已连接
   */
  isConnected() {
    return this.ws && this.ws.readyState === WebSocket.OPEN
  }

  /**
   * 是否正在重连
   */
  getIsReconnecting() {
    return this.isReconnecting
  }

  /**
   * 获取重连次数
   */
  getReconnectAttempts() {
    return this.reconnectAttempts
  }
}

// 创建默认的WebSocket客户端实例（用于报警）
let alarmWebSocketClient = null

/**
 * 获取报警WebSocket客户端
 */
export function getAlarmWebSocketClient() {
  if (!alarmWebSocketClient) {
    alarmWebSocketClient = new WebSocketClient('/websocket/alarm', {
      reconnectInterval: 3000, // 初始重连间隔3秒
      maxReconnectInterval: 30000, // 最大重连间隔30秒
      maxReconnectAttempts: 0, // 0表示无限重连
      heartbeatInterval: 30000, // 心跳间隔30秒
      heartbeatTimeout: 60000, // 心跳超时60秒（应该是心跳间隔的2倍，给网络延迟留出足够时间）
      useExponentialBackoff: true // 使用指数退避策略
    })
  }
  return alarmWebSocketClient
}

/**
 * 关闭报警WebSocket连接
 */
export function closeAlarmWebSocket() {
  if (alarmWebSocketClient) {
    alarmWebSocketClient.close()
    alarmWebSocketClient = null
  }
}

export default WebSocketClient

